/**
 * 
 */
package jmine.tec.utils.collection;

import java.util.Collection;
import java.util.List;

/**
 * <i>DropTree</i> é uma árvore de organização hierárquica de elementos que chamamos aqui de <i>dropables</i>.
 * <p>
 * Esta árvore trata a inserção de seus nó de maneira hierárquica, baseando-se na implementação de Dropable.
 * <p>
 * Toda <i>drop tree</i> deve conter um nó cabeça, cujo seus nodes são acessados via o método <i>getHeadNodes</i>.
 * <p>
 * Quando um nó é inserido na árvore, este deve "escorrer" por entre os nós que compoem a árvore até que não exista um nó "escorrível" em
 * algum nível da árvore. Devemos entender que para que um nó "escorra" em um determinado nível, o nó daquele nível deve perguntar a todos
 * seus nós filhos se o nó que está sendo inserido consegue ou não "escorrer" por ele. Caso consiga, delega-se esta operação ao nó filho e
 * assim por diante. Caso não exista nenhum nó na árvore que permita o que o nó a ser inserido "escorra", este nó deve ir para o conjunto
 * aqui chamado de <i>sink</i> (ralo). Este conjunto está disponível através do método <i>getSink</i>.
 * <p>
 * A árvore também disponibiliza um método <i>asList</i>, o qual devolve todos os <i>pools</i> de nós não vazios armazenados por entre os
 * filhos. Um <i>pool</i> é um conjunto de nós que não conseguiram "escorrer" por entre os filhos do nó que os guarda.
 * <p>
 * Note que não há diferença entre os nós que são inseridos e os nós que compoem a árvore. O que diferencia tais nós e a maneira com que são
 * inseridos na árvore. Para inserir nós no momento de criação da árvore, deve ser invocado o método <i>insertNode</i>. Este método
 * executará o algorítmo de "escorrimento" através dos nós da árvore, e irá inseri-lo em seu devido lugar. Algo importante a se considerar
 * no momento de criação da árvore é o fato de que a ordem que os nós filhos serão percorridos durante as inserções está a cargo da
 * implementação da árvore, podendo variar de implementação para implementação. Já para inserir nós que farão parte dos <i>pools</i> da
 * árvore, deve-se invocar o método <i>add</i>. Este método apenas executa normalmente o algorítmo de "escorrimento".
 * <p>
 * 
 * @author gigante
 * @param <T> o parâmetro para Dropable
 */
public interface DropTree<T> {

    /**
     * Adiciona na árvore o nó de maneira que este fará parte de algum pool da árvore, ou simplesmente irá "escorrer" para o sink.
     * 
     * @param node o nó a ser inserido.
     */
    void add(Dropable<T> node);

    /**
     * Devolve uma lista ordenada com todos os pools não vazios de todos os nós. Note que o sink não está incluso nesta lista.
     * 
     * @return a lista com os conjuntos do nós exceto o sink.
     */
    List<Collection<Dropable<T>>> asList();

    /**
     * Adiciona o node passado na árvore. Este nó representará um "duto" por onde "escorrerão" os nó que serão adicionados aos pools da
     * árvore.
     * 
     * @param node o node a ser adicionado.
     */
    void insertNode(Dropable<T> node);

    /**
     * Devolve a lista com os nós que são filhos diretos da head da árvore. Estes nós são os "dutos" da cabeça e não os nós que estão no
     * pool, até porque se a cabeça possuir algum nó não "duto", este estará no sink.
     * 
     * @return a lista com o primeiro nível da árvore. É devolvida uma lista para caso alguma implementação mantenha ordem de elementos,
     * esta ordem seja preservada, o que não garante que os elementos virão sempre na mesmo ordem nesta lista.
     */
    List<Dropable<T>> getHeadNodes();

    /**
     * Devolve os filhos de um nó específico da árvore. Devolve <code>null</code> se não houver tal nó na árvore. Estes filhos são "dutos"
     * do nó passado.
     * 
     * @param d o dropable a ser buscado na árvore. Este dropable deve ser buscado entre os dutos e não dentro dos pools de cada nó.
     * @return a lista com os "dutos" filhos de d
     */
    List<Dropable<T>> getNodesFrom(Dropable<T> d);

    /**
     * Este método devolve o pool de um determinado nó da árvore. Caso não exista tal nó, deve ser devolvido <code>null</code>.
     * 
     * @param d o node da árvore que representa um "duto"
     * @return o pool do nó passado, <code>null</code> caso não haja tal nó. É devolvido em lista para preservar uma possível ordenação de
     * algum implementação.
     */
    List<Dropable<T>> getValuesOf(Dropable<T> d);

    /**
     * Devolve os elementos que não "escorreram" por nenhum dos "dutos" da árvore.
     * 
     * @return a lista com o sink da árvore. Ordenação é responsabilidade da implementação. Caso não haja elementos no sink, deve ser
     * devolvido <code>null</code>.
     */
    List<Dropable<T>> getSink();
}
